/**
 * @(#)CodeEntityReturnRelation.java, 2008-4-30.
 * Copyright 2008  Program Analysis Research Group(PARG),Institute of Software, Peking University.
 * All rights reserved.
 */
package edu.pku.sei.pgie.analyzer.internal.relation;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.ArrayType;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.QualifiedType;
import org.eclipse.jdt.core.dom.SimpleType;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.TypeDeclaration;

import edu.pku.sei.pgie.analyzer.internal.CodeEntitySymbolTable;

/**
 * @author HeLi
 */
public class CodeEntityReturnRelation extends AbstractCodeEntityRelation {

    class ReturnVisitor extends ASTVisitor {
        List<String[]> container;

        Stack<String> typeDeclarationStack;

        public ReturnVisitor() {
            this.container = new ArrayList<String[]>();
            typeDeclarationStack = new Stack<String>();
        }

        public List<String[]> getResult() {
            return container;
        }

        public boolean visit(TypeDeclaration node) {
            ITypeBinding typeBinding = node.resolveBinding();
            if (typeBinding == null)
                return false;
            String fqn = typeBinding.getQualifiedName();
            typeDeclarationStack.push(fqn);
            return true;
        }

        public void endVisit(TypeDeclaration node) {
            if (!typeDeclarationStack.isEmpty()) {
                typeDeclarationStack.pop();
            }
        }

        public boolean visit(MethodDeclaration node) {
            Type returnType = node.getReturnType2();
            if (returnType == null) {
                return true;
            }
            String typeName = (String) typeDeclarationStack.peek();
            if (returnType instanceof QualifiedType
                    || returnType instanceof SimpleType) {
                ITypeBinding binding = returnType.resolveBinding();
                if (binding == null)
                    return true;
                String fqn = binding.getQualifiedName();
                container.add(new String[] {
                    typeName, fqn
                });
            } else if (returnType instanceof ArrayType) {
                while (((ArrayType) returnType).getElementType() instanceof ArrayType) {
                    returnType = ((ArrayType) returnType).getElementType();
                }
                if (returnType instanceof SimpleType
                        || returnType instanceof QualifiedType) {
                    ITypeBinding binding = returnType.resolveBinding();
                    if (binding == null)
                        return true;
                    String fqn = binding.getQualifiedName();
                    container.add(new String[] {
                        typeName, fqn
                    });
                }
            }
            return true;
        }
    }

    public String[][] collectCallBack(CompilationUnit root,
            CodeEntitySymbolTable symbolTable) throws Exception {
        ReturnVisitor visitor = new ReturnVisitor();
        List<String[]> result = visitor.getResult();
        return result.toArray(new String[result.size()][]);
    }
}
